package estados;
import interfaces.IEstado;

import java.util.ArrayList;
import java.util.List;

import exceptions.EstadoJogoDaVelhaException;


public class EstadoJogoDaVelha implements IEstado {
	
	public static final char computador = 'x';
	public static final char pessoa = 'o';;
	private double utilidade = 0;
	
	public static short tam = 3;
	
	private char[][] matriz = new char[tam][tam];
	
	private char ultimoJogador = ' ';
	private EstadoJogoDaVelha proxJogada = null;
	
	public EstadoJogoDaVelha() {
        for (int linha=0;linha<tam;linha++) {
            for (int coluna=0;coluna<tam;coluna++) {
                matriz[linha][coluna] = ' ';
            }
        }
    }
	public EstadoJogoDaVelha(EstadoJogoDaVelha estadoAnterior, char jogador) {
		// TODO Auto-generated constructor stub
		//copia a matriz 
		for (int linha=0;linha<tam;linha++) {
            for (int coluna=0;coluna<tam;coluna++) {
                matriz[linha][coluna] = estadoAnterior.matriz[linha][coluna];
            }
        }
		//define de quem é a vez
        ultimoJogador = jogador;
	}

	public EstadoJogoDaVelha(char[][] matriz, char jogador) {
		// TODO Auto-generated constructor stub
		for (int linha=0;linha<tam;linha++) {
            for (int coluna=0;coluna<tam;coluna++) {
                this.matriz[linha][coluna] = matriz[linha][coluna];
            }
        }
		ultimoJogador = jogador;
	}

	@Override
	public List<IEstado> sucessores() {
		// TODO Auto-generated method stub
		char proximoJogador = pessoa;
		if (ultimoJogador == pessoa) proximoJogador = computador;
		
		List<IEstado> sucessores = new ArrayList<IEstado>();
		
		for (int linha = 0; linha < tam; linha++) {
			for (int coluna = 0; coluna < tam; coluna++) {
				if (celulaLivre(linha, coluna)){					
					EstadoJogoDaVelha novo = new EstadoJogoDaVelha( this, proximoJogador);
                    novo.matriz[linha][coluna] = proximoJogador;
                    sucessores.add( novo );
				}
			}
			
		}
		return sucessores;
	}

	@Override
	public boolean isTerminal() {
		// TODO Auto-generated method stub
		return ganha(computador) || ganha(pessoa) || contaBrancos() == 0; 
	}

	
	@Override
	public void setProxJogada(IEstado sucessor) {
		// TODO Auto-generated method stub
		
			this.proxJogada = (EstadoJogoDaVelha)sucessor;
		
		
	}
	
	public double calculaUtilidade() {
        if (ganha(computador)) utilidade =1;
        else if (ganha(pessoa)) utilidade =-1;
        else utilidade = 0;
        return utilidade;
    }
       
	
	public void jogar( int linha, int coluna, char jogador) throws EstadoJogoDaVelhaException{
		if (!celulaLivre(linha, coluna)){
			String message = "A CÉLULA JA ESTÁ PREENCHIDA. FAVOR SELECIONAR OUTRA CÉLULA.";
			throw new EstadoJogoDaVelhaException(new Exception(message));
		}
		else  matriz[linha][coluna] = jogador;
		
	}

	private boolean celulaLivre(int linha, int coluna) {
		return matriz[linha][coluna] == ' ';
	}
	
	public void setJogador(char jogador) {
		this.ultimoJogador = jogador;
	}

	public char getJogador() {
		return this.ultimoJogador;
	}

	private boolean ganha(char jogador) {
        for (int i=0;i<tam;i++) {
            if (colunaIgualA(i, jogador) || linhaIgualA(i, jogador)) {
                return true;
            }
        }
        
        if (diagonalPrincialIgualA(jogador) ||  diagonalSecundariaIgualA(jogador)) {
            return true;
        }
        
        return false;
    }
	private boolean linhaIgualA(int linha, char jogador) {
        for (int coluna=0;coluna<tam;coluna++) {
            if (matriz[linha][coluna] != jogador) {
                return false;
            }
        }
        return true;
    }
    
    private boolean colunaIgualA(int coluna, char jogador) {
        for (int linha=0;linha<tam;linha++) {
            if (matriz[linha][coluna] != jogador) {
                return false;
            }
        }
        return true;
    }
    
    private boolean diagonalPrincialIgualA(char jogador) {
        for (int i=0;i<tam;i++) {
            if (matriz[i][i] != jogador) {
                return false;
            }
        }
        return true;
    }
    
    private boolean diagonalSecundariaIgualA(char jogador) {
        for (int i=0;i<tam;i++) {
            int l = tam-i-1;
            if (matriz[l][i] != jogador) {
                return false;
            }
        }
        return true;
    }

	private int contaBrancos() {
        int soma = 0;
        for (int linha=0;linha<tam;linha++) {
            for (int coluna=0;coluna<tam;coluna++) {
                if (celulaLivre(linha, coluna)) {
                    soma++;
                }
            }
        }
        return soma;
    }
	


	public EstadoJogoDaVelha getProxJogada() {
		return proxJogada;
	}
	
	public String toString() {
        StringBuffer r = new StringBuffer("\n");
        for (int linha=0;linha<tam;linha++) {
            r.append((linha+1) + ":   ");
            for (int coluna=0;coluna<tam;coluna++) {
                r.append(matriz[linha][coluna]);
                if (coluna+1<tam) {
                    r.append(" | ");
                }
            }
            if (linha+1<tam) {
                r.append("\n     ----------\n");
            }
        }
        return r + "       u="+ getUtilidade() + "\n";
    }

	public void setUtilidade(double utilidade) {
		this.utilidade = utilidade;
	}

	public double getUtilidade() {
		return utilidade;
	}

}
